/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "NodeBase.h"
#include <Converter.h>
#include <xml/Stream.h>
#include <xml/Saver.h>
#include <safe_new.h>
#include <logs/Log.h>

namespace liba {
namespace lib3d {
namespace node {

const Atom NodeBase::position_name( "Position" );
const Atom NodeBase::rotation_name( "Rotation" );
const Atom NodeBase::scale_name( "Scale" );

NodeBase::NodeBase( const Atom & name )
	: animate::Node( name )
	, localMatrixDirty( true )
	, invertLocalMatrixDirty( true )
{
	this->RegisterProperty(position_name, &this->position);
	this->RegisterProperty(rotation_name, &this->rotation);
	this->RegisterProperty(scale_name, &this->scale);

	this->position = Vector(0, 0, 0);
	this->rotation = Vector(0, 0, 0);
	this->scale = Vector(1, 1, 1);
}
	
NodeBase::~NodeBase()
{ }
	
void NodeBase::set_matrix( const Matrix & mat )
{
	Matrix tmp_mat = mat;
	float s0 = float(sqrt( tmp_mat.rc(0, 0)*tmp_mat.rc(0, 0) + tmp_mat.rc(1, 0)*tmp_mat.rc(1, 0) + tmp_mat.rc(2, 0)*tmp_mat.rc(2, 0) ));
	float s1 = float(sqrt( tmp_mat.rc(0, 1)*tmp_mat.rc(0, 1) + tmp_mat.rc(1, 1)*tmp_mat.rc(1, 1) + tmp_mat.rc(2, 1)*tmp_mat.rc(2, 1) ));
	float s2 = float(sqrt( tmp_mat.rc(0, 2)*tmp_mat.rc(0, 2) + tmp_mat.rc(1, 2)*tmp_mat.rc(1, 2) + tmp_mat.rc(2, 2)*tmp_mat.rc(2, 2) ));

	scale = Vector( s0 , s1 , s2 );
	
	tmp_mat.rc( 0, 0 ) /= s0;
	tmp_mat.rc( 1, 0 ) /= s0;
	tmp_mat.rc( 2, 0 ) /= s0;

	tmp_mat.rc( 0, 1 ) /= s1;
	tmp_mat.rc( 1, 1 ) /= s1;
	tmp_mat.rc( 2, 1 ) /= s1;

	tmp_mat.rc( 0, 2 ) /= s2;
	tmp_mat.rc( 1, 2 ) /= s2;
	tmp_mat.rc( 2, 2 ) /= s2;

	position = tmp_mat.shift();
	
	tmp_mat.rc( 0, 3 ) = 0;
	tmp_mat.rc( 1, 3 ) = 0;
	tmp_mat.rc( 2, 3 ) = 0;

	rotation = Matrix::factorization( tmp_mat );
	
	InvalidateLocalMatrix();
}

bool NodeBase::on_attribute( xml::Provider * prov, const std::string & name, const std::string & value )
{
	if ( name == "Name" )
	{
		Atom localName;
		if (!converter::convert( value, &localName ))
			return false;
		this->SetName(localName);
		return true;
	}
	else if ( name == "Position" )
	{
		Vector localPosition;
		if (!converter::convert( value, &localPosition ))
			return false;

		this->position = localPosition;
		InvalidateLocalMatrix();
		return true;
	}
	else if ( name == "Rotation" )
	{
		Vector localRotation;
		if (!converter::convert( value, &localRotation ))
			return false;

		this->rotation = localRotation;
		InvalidateLocalMatrix();
		return true;
	}
	else if ( name == "Scale" )
	{
		Vector localScale;
		if (!converter::convert( value, &localScale ))
			return false;

		this->scale = localScale;
		InvalidateLocalMatrix();
		return true;
	}
	return false;
}

void NodeBase::on_save_attributes( xml::SaverBase * saver )const
{
	saver->save_attribute("Name", this->GetName().get_str());
	if(position.Get() != Vector(0,0,0))
		saver->save_attribute("Position", position.Get());

	if(rotation.Get() != Vector(0,0,0))
		saver->save_attribute("Rotation", rotation.Get());

	if(scale.Get() != Vector(1,1,1))
		saver->save_attribute("Scale", scale.Get());
}

} // namespace node
} // namespace lib3d
} // namespace liba


